package com.fuchuang.seckillsystem.service.impl;

import com.fuchuang.seckillsystem.dto.KeyConstants;
import com.fuchuang.seckillsystem.dto.RecordQuery;
import com.fuchuang.seckillsystem.dto.TimeConstants;
import com.fuchuang.seckillsystem.dto.UserQuery;
import com.fuchuang.seckillsystem.entity.*;
import com.fuchuang.seckillsystem.exception.GlobalException;
import com.fuchuang.seckillsystem.mapper.AccountMapper;
import com.fuchuang.seckillsystem.mapper.UserMapper;
import com.fuchuang.seckillsystem.service.IOverRecordService;
import com.fuchuang.seckillsystem.service.IRoleService;
import com.fuchuang.seckillsystem.service.IUserService;
import com.fuchuang.seckillsystem.utils.MyStringUtils;
import com.fuchuang.seckillsystem.utils.Sm4Utils;
import com.fuchuang.seckillsystem.vo.RespBeanEnum;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements IUserService {
    
    @Resource
    private UserMapper userMapper;
    
    @Resource
    private AccountMapper accountMapper;
    
    @Autowired
    private IRoleService roleService;
    
    @Autowired
    private IOverRecordService overRecordService;
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    
    @Autowired
    private Sm4Utils sm4Utils;
    
    private static final Double BASE_ACCOUNT = 50000.00;
    
    public KieBase getKieBase() {
        DefaultListableBeanFactory defaultListableBeanFactory =
                (DefaultListableBeanFactory) applicationContext.getAutowireCapableBeanFactory();
        return (KieBase) defaultListableBeanFactory.getBean("kieBase");
    }
    
    
    @Override
    public MyUserDetails findUserDetailsByUsername(String username) {
        //从redis中查询是否有该用户数据
        MyUserDetails redisUserDetails = (MyUserDetails) redisTemplate.opsForValue().get(KeyConstants.USER_DETAIL + username);
        if (redisUserDetails != null) {
            return redisUserDetails;
        }
        User user = userMapper.queryUserByUsername(username);
        if (!Objects.isNull(user)) {
            MyUserDetails userDetails = new MyUserDetails();
            //进行初筛
            Integer isPass = passScreening(user.getIdcard());
            userDetails.setStatus(isPass);
            //补充框架所需的用户参数
            userDetails.setId(user.getId());
            userDetails.setUsername(username);
            userDetails.setPassword(user.getPassword());
            Collection<? extends GrantedAuthority> authorities = getAuthorities(user.getId());
            //将角色权限注入到框架对象中
            userDetails.setAuthorities(authorities);
            //将该用户保存到redis中，设置过期时间为1天
            redisTemplate.opsForValue().set(KeyConstants.USER_DETAIL + username, userDetails, TimeConstants.USER_DETAIL, TimeUnit.HOURS);
            return userDetails;
        }
        return null;
    }
    
    /**
     * 查询用户拥有的角色
     */
    private Collection<? extends GrantedAuthority> getAuthorities(Integer userId) {
        Set<GrantedAuthority> authorities = new HashSet<>();
        //获取用户所拥有的角色
        List<Role> roles = roleService.getUserRole(userId);
        roles.forEach(role -> {
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
            authorities.add(simpleGrantedAuthority);
        });
        return authorities;
    }
    
    /**
     * 筛选用户
     */
    private Integer passScreening(String idcard) {
        //获取需要筛选的银行用户数据
        SystemUser systemUser = userMapper.querySystemUserByIdcard(idcard);
        systemUser.setStatus(1);
        //获取keiSession
        KieBase kieBase = getKieBase();
        KieSession kieSession = kieBase.newKieSession();
        kieSession.getAgenda().getAgendaGroup("sign").setFocus();
        //插入银行用户
        kieSession.insert(systemUser);
        kieSession.fireAllRules();
        if (systemUser.getStatus() == 1) {
            RecordQuery recordQuery = (RecordQuery) redisTemplate.opsForValue().get(KeyConstants.RECORD_QUERY);
            if (recordQuery == null) {
                recordQuery = new RecordQuery();
                kieSession.insert(recordQuery);
                kieSession.fireAllRules();
                System.out.println(recordQuery);
                redisTemplate.opsForValue().set(KeyConstants.RECORD_QUERY, recordQuery);
            }
            if (recordQuery.getOverdueMoney() != null) {
                Integer overCount = overRecordService.getOverCount(recordQuery);
                if (overCount > recordQuery.getCount()) {
                    systemUser.setStatus(0);
                }
            }
        }
        kieSession.dispose();
        return systemUser.getStatus();
    }
    
    
    @Override
    @Transactional
    public void register(User user) {
        checkRegisterParams(user);
        //对密码和身份证进行加密
        String encodePassword = sm4Utils.encrypt(user.getPassword());
        String encodeIdcard = sm4Utils.encrypt(user.getIdcard());
        //判断用户名是否存在
        User result = userMapper.queryUserByUsername(user.getUsername());
        if (result != null) {
            throw new GlobalException(RespBeanEnum.USERNAME_HAS_EXIST_ERROR);
        }
        //判断身份证是否被注册过了
        result = userMapper.queryUserByIdcard(encodeIdcard);
        if (result != null) {
            throw new GlobalException(RespBeanEnum.IDCARD_HAST_EXIST);
        }
        //通过查询系统用户信息，判断用户身份是否正确
        SystemUser systemUser = userMapper.querySystemUserByIdcard(encodeIdcard);
        if (systemUser == null) {
            throw new GlobalException(RespBeanEnum.IDENTITY_ERROR);
        }
        if (!user.getRealName().equals(systemUser.getRealName())) {
            throw new GlobalException(RespBeanEnum.IDENTITY_ERROR);
        }
        //补充参数
        user.setAge(systemUser.getAge());
        user.setPassword(encodePassword);
        user.setAge(systemUser.getAge());
        user.setIdcard(encodeIdcard);
        Date date = new Date();
        user.setCreateTime(date);
        user.setUpdateTime(date);
        int rows = userMapper.insertSelective(user);
        if (rows != 1) {
            throw new GlobalException(RespBeanEnum.REGISTER_ERROR);
        }
        //给用户赋予普通用户角色  普通用户角色 id : 4
        List<Integer> roleIds = new ArrayList<>();
        roleIds.add(4);
        roleService.grant(user.getId(), roleIds);
        //生成账户信息
        Random random = new Random();
        Account account = new Account();
        account.setBalance(new BigDecimal(BASE_ACCOUNT + random.nextInt(150000)));
        account.setUserId(user.getId());
        account.setIsValid(1);
        account.setCreateTime(date);
        account.setUpdateTime(date);
        accountMapper.insert(account);
    }
    
    /**
     * 对注册用户参数进行校验
     */
    private void checkRegisterParams(User user) {
        //判断参数是否为空
        if (MyStringUtils.isBlank(user.getUsername()) || MyStringUtils.isBlank(user.getPassword())
                || MyStringUtils.isBlank(user.getRealName()) || MyStringUtils.isBlank(user.getIdcard())) {
            throw new GlobalException(RespBeanEnum.PARAMS_ERROR);
        }
    }
    
    
    @Override
    @Transactional
    public void update(User user) {
        checkUpdateParams(user);
        //判断用户名称是否重复
        User result = userMapper.queryUserByUsername(user.getUsername());
        if (result != null) {
            //如果该名称不是该用户的
            if (!result.getId().equals(user.getId())) {
                throw new GlobalException(RespBeanEnum.USERNAME_HAS_EXIST_ERROR);
            }
        }
        //判断需要修改的用户是否存在
        User idUser = userMapper.selectByPrimaryKey(user.getId());
        if (idUser == null) {
            throw new GlobalException(RespBeanEnum.USER_NOT_EXIST_ERROR);
        }
        //判断密码是否修改，如果修改则加密密码
        if (user.getPassword() != null) {
            String encode = sm4Utils.encrypt(user.getPassword());
            user.setPassword(encode);
        }
        //设置参数
        user.setUpdateTime(new Date());
        int row = userMapper.updateByPrimaryKeySelective(user);
        if (row != 1) {
            throw new GlobalException(RespBeanEnum.UPDATE_ERROR);
        }
        //删除redis中登录用户对象和秒杀系统用户对象
        redisTemplate.delete(KeyConstants.USER_DETAIL + user.getUsername());
        redisTemplate.delete(KeyConstants.USER_INFO + user.getId());
    }
    
    /**
     * 对更新的用户信息参数进行校验
     */
    private void checkUpdateParams(User user) {
        if (MyStringUtils.isBlank(user.getUsername())
                && MyStringUtils.isBlank(user.getPassword())
                && MyStringUtils.isBlank(user.getPhone())) {
            //如果为修改值
            throw new GlobalException(RespBeanEnum.PARAMS_ERROR);
        }
    }
    
    
    @Override
    public User getUser(Integer userId) {
        //到redis中获取用户信息
        User user = (User) redisTemplate.opsForValue().get(KeyConstants.USER_INFO + userId);
        if (user == null) {
            user = userMapper.selectByPrimaryKey(userId);
            redisTemplate.opsForValue().set(KeyConstants.USER_INFO + userId, user, TimeConstants.USER_INFO, TimeUnit.DAYS);
        }
        user.setPassword(null);
        user.setIdcard(null);
        return user;
    }
    
    @Override
    public Map<String, Object> getAllUser(UserQuery userQuery) {
        Map<String, Object> map = new HashMap<>();
        if (MyStringUtils.isNotBlank(userQuery.getIdcard())) {
            userQuery.setIdcard(sm4Utils.encrypt(userQuery.getIdcard()));
        }
        PageHelper.startPage(userQuery.getPage(), userQuery.getLimit());
        PageInfo<User> pageInfo = new PageInfo<>(userMapper.queryAllUser(userQuery));
        map.put("list", pageInfo.getList());
        map.put("count", pageInfo.getTotal());
        return map;
    }
    
}
